package com.alks.function.service.impl.stockdept.pcfactorystockquery;

import com.alibaba.excel.util.StringUtils;
import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.dto.SysUserTokenDTO;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.service.RedisService;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.common.utils.beanutils.BeanUtil;
import com.alks.common.utils.beanutils.ObjectUtils;
import com.alks.common.utils.stringUtils.ZStringUtils;
import com.alks.entity.data.entity.*;
import com.alks.entity.data.page.PageRecord;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.InDataException;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.finance.costcheck.PcPackDetailsReq;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.CsmDetailDto;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.LotMtlDto;
import com.alks.function.data.request.stockdept.pcfactorystockwork.CsmDetAddRequest;
import com.alks.function.data.request.stockdept.pcfactorystockwork.CsmDetRequest;
import com.alks.function.data.request.stockdept.pcfactorystockwork.LotMtlRequest;
import com.alks.function.data.vo.controller.stockdept.MtlDocumentVo;
import com.alks.function.mapper.stockdept.pcfactorystockquery.*;
import com.alks.function.service.stockdept.pcfactorystockquery.IPackMtlIOService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.MathContext;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.alks.entity.data.enums.RedisKeyEnum.PACK_IO;
import static com.alks.entity.data.enums.ResultCodeEnum.INPUT_ERROR;

@Slf4j
@Service
@RequiredArgsConstructor
public class PackMtlIOServiceImpl extends ServiceImpl<SD_SQ_PcSlipTempPackMapper, PcSlipTempPack> implements IPackMtlIOService {
    private final SD_SQ_PcSlipTempPackMapper tempPackMapper;
    private final SD_SQ_PcSlipDetailPackMapper detailPackMapper;
    private final SD_SQ_PcPackDetailMapper lotMtlMapper;
    private final SD_SQ_PcMtlAccPackMapper accMapper;
    private final SD_SQ_SdMaterialMapper comMtlMapper;
    private final RedisService redisService;

    @Override
    public ResponseInfo getPackTempQuery(String slipType) {
        String companyId = UserIdThread.get().getCompanyId();
        /*获取数据*/
        List<PcSlipTempPack> temps = lambdaQuery()
                .eq(PcSlipTempPack::getSysUser, UserIdThread.get().getLoginName())
                .eq(PcSlipTempPack::getSlipType, slipType)
                .eq(PcSlipTempPack::getCompanyId,companyId).list();
        List<CsmTempDto> dtos = BeanUtil.copyList(temps, CsmTempDto.class);
        return ResponseInfo.ok(dtos);
    }

    @Override
    @AutoPageAop
    public ResponseInfo getPackLotMtlQuery(LotMtlRequest request, String slipType) {
        String companyId = UserIdThread.get().getCompanyId();
        /*获取数据*/
        List<LotMtlDto> dtos = lotMtlMapper.getPackLotMtlQuery(request, slipType,companyId);
        Page<LotMtlDto> page = (Page<LotMtlDto>) dtos;
        /*封装数据*/
        Map<String, Object> map = new HashMap<>();
        map.put("total", page.getTotal());
        map.put("dtos", dtos);
        return ResponseInfo.ok(map);
    }

    @Override
    @AutoPageAop
    public ResponseInfo getPackDetQuery(CsmDetRequest request, String slipType) {
        String companyId = UserIdThread.get().getCompanyId();
        /*获取数据*/
        LambdaQueryWrapper<PcSlipDetailPack> wrapper = new LambdaQueryWrapper<PcSlipDetailPack>()
                .eq(request.getSendNo() != null && !request.getSendNo().isEmpty(), PcSlipDetailPack::getSendNo, request.getSendNo())
                .eq(request.getSlipNo() != null && !request.getSlipNo().isEmpty(), PcSlipDetailPack::getSlipNo, request.getSlipNo())
                .eq(request.getLotNo() != null && !request.getLotNo().isEmpty(), PcSlipDetailPack::getLotNo, request.getLotNo())
                .eq(request.getVendorNo() != null && !request.getVendorNo().isEmpty(), PcSlipDetailPack::getVendorNo, request.getVendorNo())
                .eq(request.getMtlName() != null && !request.getMtlName().isEmpty(), PcSlipDetailPack::getMtlName, request.getMtlName())
                .eq(request.getSlipReason() != null && !request.getSlipReason().isEmpty(),  PcSlipDetailPack::getSlipReason, request.getSlipReason())
                .ge(request.getSlipDateStart() != null, PcSlipDetailPack::getSlipDate, request.getSlipDateStart())
                .le(request.getSlipDateEnd() != null, PcSlipDetailPack::getSlipDate, request.getSlipDateEnd())
                .eq(PcSlipDetailPack::getCompanyId,companyId)
                .eq(PcSlipDetailPack::getSysUser, UserIdThread.get().getLoginName())
                .eq(PcSlipDetailPack::getSlipType, slipType)
                .orderByDesc(PcSlipDetailPack::getSlipNo, PcSlipDetailPack::getSysDate);
        List<PcSlipDetailPack> details = detailPackMapper.selectList(wrapper);
        List<CsmDetailDto> dtos = BeanUtil.copyList(details, CsmDetailDto.class);
        PageRecord<CsmDetailDto> record = new PageRecord<>(dtos);
        if (request.getPageSize()!=-1 && request.getPageNum()!= -1) {
            Page<PcSlipDetailPack> page = (Page<PcSlipDetailPack>) details;
            record.setTotal(page.getTotal());
        }
        return ResponseInfo.ok(record);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void packTempAdd(List<Map<String, String>> request, String slipType) {
        String companyId = UserIdThread.get().getCompanyId();
        /*如果没有选中数据则直接返回*/
        List<PcSlipTempPack> packs;
        if (ArrayUtils.isEmpyt(request) || StringUtils.isBlank(request.get(0).get("mtlNo"))) {
            throw new InDataException("请勾选");
        }
        if (request.get(0).get("lotNo") != null && !request.get(0).get("lotNo").isEmpty()) {
            /*存在指令则从指令库寻找数据*/
            packs = lotMtlMapper.packTempAddQuery(request);
            /*补充未下单不能入库*/
//            if(packs.stream().anyMatch(a -> StringUtils.isBlank(a.getPurNo()))){
//                throw new ServiceErrorException("有未下单数据");
//            }
        } else {
            /*没有指令数据则直接寻找通用材料*/
            packs = comMtlMapper.packTempAddQuery(request);
        }

        /*获取表中当前最大序号并写入*/
        PcSlipTempPack temp = lambdaQuery()
                .select(PcSlipTempPack::getItem)
                .eq(PcSlipTempPack::getSysUser, UserIdThread.get().getLoginName())
                .eq(PcSlipTempPack::getSlipType, slipType)
                .orderByDesc(PcSlipTempPack::getItem)
                .last("LIMIT 1").one();
        Integer item = temp == null ? 0 : temp.getItem() + 1;
        for (PcSlipTempPack pack : packs) {
            pack.setCompanyId(companyId);
            pack.setStockNo("X3");
            pack.setItem(item);
            pack.setSlipType(slipType);
            pack.setSysUser(UserIdThread.get().getLoginName());
            pack.setSysDate(LocalDateTime.now());
            tempPackMapper.insert(pack);
            item++;
        }
    }

    @Override
    public ResponseInfo packTempUp(String item, Float qty, String remark, String slipType) {
        /*更新数据*/
        lambdaUpdate().eq(PcSlipTempPack::getItem, item)
                .eq(PcSlipTempPack::getSysUser, UserIdThread.get().getLoginName())
                .eq(PcSlipTempPack::getSlipType, slipType)
                .set(PcSlipTempPack::getQty, qty)
                .set(PcSlipTempPack::getRemark, remark)
                .update();
        return ResponseInfo.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String packDetailAdd(CsmDetAddRequest request, String slipType) {
        final String outType = "O";
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        String loginName = tokenDTO.getLoginName();
        String companyId = tokenDTO.getCompanyId();
        /*获取要取出的数据*/
        LambdaQueryWrapper<PcSlipTempPack> tempWrapper = new LambdaQueryWrapper<PcSlipTempPack>()
                .eq(PcSlipTempPack::getCompanyId, companyId)
                .gt(PcSlipTempPack::getQty,0)
                .eq(PcSlipTempPack::getSlipType, slipType)
                .eq(PcSlipTempPack::getSysUser, loginName);
        List<PcSlipTempPack> temps = tempPackMapper.selectList(tempWrapper);
        /*处理整合相同mtlNo的qty*/
        Map<String, Float> mtlQty = new HashMap<>();
        for (PcSlipTempPack temp : temps) {
            String key = temp.getMtlNo();
            if (temp.getQty() != null && temp.getQty().compareTo(BigDecimal.ZERO) > 0) {
                mtlQty.put(key, mtlQty.get(key) == null ? temp.getQty().floatValue() : BigDecimal.valueOf(mtlQty.get(key)).add(temp.getQty()).floatValue());
            }
        }
        if (mtlQty.isEmpty()) {
            throw new ServiceErrorException("没有数量大于零的数据，无法入库");
        }
        List<String> mtlNos = new ArrayList<>(mtlQty.keySet());
        /*获取对应材料库存*/
        LambdaQueryWrapper<PcMtlAccPack> accWrapper = new LambdaQueryWrapper<PcMtlAccPack>()
                .select(PcMtlAccPack::getMtlNo, PcMtlAccPack::getStkQty)
                .eq(PcMtlAccPack::getCompanyId, companyId)
                .in(PcMtlAccPack::getMtlNo, mtlNos);
        List<PcMtlAccPack> packs = accMapper.selectList(accWrapper);
        Map<String, BigDecimal> stkQty = new HashMap<>();
        if (ArrayUtils.isNoEmpyt(packs)) {
        stkQty = packs.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(
                        PcMtlAccPack::getMtlNo,
                        pack -> Optional.ofNullable(pack.getStkQty()).orElse(BigDecimal.ZERO),
                        BigDecimal::add,
                        HashMap::new
                ));
        }
        /*出库逻辑*/
        if (outType.equals(slipType)) {
            if (stkQty.isEmpty()){
                throw new ServiceErrorException("没有库存数据，无法出库");
            }
            /*判断库存量是否充足*/
            for (String mtlNo : mtlNos) {
                if (stkQty.get(mtlNo) == null || stkQty.get(mtlNo).compareTo(BigDecimal.valueOf(mtlQty.get(mtlNo))) < 0) {
                    throw new ServiceErrorException("库存不足，物料编号：" + mtlNo);
                }
            }
            /*改变库存量*/
            accMapper.packDetailOutAdd(mtlQty);
        } else {
            /*入库逻辑*/
            ArrayList<String> mtlFinds = new ArrayList<>(stkQty.keySet());
            List<String> miss = ArrayUtils.findMiss(mtlNos, mtlFinds);
            /*不存在则建档*/
            if (!ArrayUtils.isEmpyt(miss)) {
                List<MtlDocumentVo> vos=new ArrayList<>();
                for (String s : miss) {
                    Map<String, PcSlipTempPack> mtlTemps = temps.stream().collect(Collectors.toMap(PcSlipTempPack::getMtlNo, a -> a,(a,b)->a));
                    PcSlipTempPack pack = mtlTemps.get(s);
                    MtlDocumentVo vo = BeanUtil.copyBean(pack, MtlDocumentVo.class);
                    vo.setInQty(pack.getQty());
                    vos.add(vo);
                }
                accMapper.mtlDocumentCreate(vos);
            }
            /*增加库存量*/
            accMapper.packDetailInAdd(mtlQty);
        }
        /*获取待写入数据并写入*/
        String slipNoCreat = redisService.slipNoCreat(PACK_IO.getKey());
        List<PcSlipDetailPack> details = BeanUtil.copyList(temps, PcSlipDetailPack.class);
        for (PcSlipDetailPack detail : details) {
            detail.setCompanyId(companyId);
            detail.setSlipNo(slipNoCreat);
            detail.setDeptNo(request.getDeptNo());
            detail.setDeptName(request.getDeptName());
            detail.setVendorNo(request.getVendorNo());
            detail.setVendorName(request.getVendorName());
            detail.setSendNo(request.getSendNo());
            detail.setSlipReason(request.getSlipReason());
            detail.setSlipDate(request.getSlipDate().atStartOfDay());
            detail.setSysDate(request.getSysDate() == null ? LocalDateTime.now() : request.getSysDate().atStartOfDay());
            detail.setSysUser(loginName);
            detailPackMapper.insert(detail);
        }
        /*删除待入库数据*/
        tempPackMapper.delete(tempWrapper);
        return slipNoCreat;
    }

    @Override
    public ResponseInfo packTempDelete(List<String> itemList, String slipType) {
        /*删除对应数据*/
        LambdaQueryWrapper<PcSlipTempPack> wrapper = new LambdaQueryWrapper<PcSlipTempPack>()
                .in(PcSlipTempPack::getItem, itemList)
                .eq(PcSlipTempPack::getSlipType, slipType)
                .eq(PcSlipTempPack::getSysUser, UserIdThread.get().getLoginName());
        tempPackMapper.delete(wrapper);
        return ResponseInfo.ok();
    }

    @Override
    @Transactional
    public ResponseInfo packDetDelete(List<Integer> idList, String slipType) {
        /*判断标志位*/
        LambdaQueryWrapper<PcSlipDetailPack> wrapper = new LambdaQueryWrapper<PcSlipDetailPack>()
                .in(PcSlipDetailPack::getId, idList)
                .eq(PcSlipDetailPack::getSlipType, slipType)
                .eq(PcSlipDetailPack::getSysUser, UserIdThread.get().getLoginName());
        List<PcSlipDetailPack> detailList = detailPackMapper.selectList(wrapper);
        if (ArrayUtils.isEmpyt(detailList)){
            throw new ServiceErrorException("数据不存在");
        }
        long cfmCount = detailList.stream().filter(t -> t.getCfmFlag()!=null && t.getCfmFlag().equals("Y")).count();
        if (cfmCount>0) {
            return ResponseInfo.error("已审核数据无法删除", INPUT_ERROR.getCode());
        }
        /*删除对应数据*/
        detailPackMapper.delete(wrapper);
        /*回滚库存*/
        for (PcSlipDetailPack detail : detailList) {
            BigDecimal qty = detail.getQty();
            String mtlNo = detail.getMtlNo();
            accMapper.packDetDelete(qty, slipType, mtlNo);
        }
        return ResponseInfo.ok();
    }

    @Override
    @AutoPageAop
    public ResponseInfo getSlipDetailPack(PcPackDetailsReq req) {
        Map<String, Object> map = new HashMap<>();
        req.setCompanyId(UserIdThread.get().getCompanyId());
        List<PcSlipDetailPacks> list = detailPackMapper.getSlipDetailPack(req);
        Page<PcSlipDetailPacks> page = (Page<PcSlipDetailPacks>) list;
        map.put("list", list);
        map.put("total", page.getTotal());
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo optionPackCheck(List<String> list, String check) {
        for (String string : list) {
            List<PcSlipDetailPacks> lists = detailPackMapper.getPcSlipPackDetail(string,UserIdThread.get().getCompanyId());
            for (PcSlipDetailPacks pcSlipDetailPacks : lists) {
                if ("2".equals(check)) {
                    if(!UserIdThread.get().getUserName().equals(pcSlipDetailPacks.getCfmUser())) throw new ServiceErrorException("不可取消检核，请确认是否为检核人");
                }
                if (ZStringUtils.isNotEmpty(pcSlipDetailPacks.getFinanceCfmFlag())) throw new ServiceErrorException("财务对账，无法修改");
                if (pcSlipDetailPacks.getPrice() == null) return ResponseInfo.error("单价不能为空");
            }
        }
        detailPackMapper.optionPackCheck(list, check, UserIdThread.get().getUserName(),UserIdThread.get().getCompanyId());
        return ResponseInfo.ok();
    }

    @Autowired
    SD_SQ_PcMtlCheckMapper checkMapper;

    @Override
    public ResponseInfo setRemarkPack(List<String> slipNos, String remark) {
        for (String slipNo : slipNos) {
            PcMtlCheck2 pcMtlCheck2 = new PcMtlCheck2();
            pcMtlCheck2.setRecNo(slipNo);
            pcMtlCheck2.setCompanyId(UserIdThread.get().getCompanyId());
            String str = checkMapper.getListByRecNo(pcMtlCheck2);
            if (str == null || "".equals(str)) {
                checkMapper.insertIntoRemark2(pcMtlCheck2, remark);
            } else {
                checkMapper.updateRemark2(pcMtlCheck2, remark);
            }
        }
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo getPcSlipPackDetail(String slipNo) {
        DecimalFormat d1 = new DecimalFormat("0.00000");
        DecimalFormat d2 = new DecimalFormat("0.00");
        List<PcSlipDetailPacks> list = detailPackMapper.getPcSlipPackDetail(slipNo,UserIdThread.get().getCompanyId());
        for (PcSlipDetailPacks detailPacks : list) {
            if (detailPacks.getPrice()!=null) detailPacks.setPrices(d1.format(detailPacks.getPrice()));
            if (detailPacks.getAmt()!=null) detailPacks.setAmts(d2.format(detailPacks.getAmt()));
        }
        return ResponseInfo.ok(list);
    }

    @Override
    public ResponseInfo savePcSlipPackDetail(List<PcSlipDetailPacks> list) {
        detailPackMapper.savePcSlipPackDetail(list);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo setUnitPrice(List<PcSlipDetailPacks> list) {
        Integer i = 0;
        for (PcSlipDetailPacks detailPacks : list) {
            if (detailPacks.getPrice()!=null && detailPacks.getPrice().doubleValue() > 0) continue;
            BigDecimal pcUnitPrice = detailPackMapper.getPcUnitPrice(detailPacks);
            if (pcUnitPrice!=null)i++;
            BigDecimal unitPrice = pcUnitPrice == null ? new BigDecimal(0) : pcUnitPrice;
            BigDecimal qty = detailPacks.getQty() == null ? new BigDecimal(0) : detailPacks.getQty();
            BigDecimal amt = unitPrice.multiply(qty, MathContext.DECIMAL32);
            detailPacks.setAmts(String.valueOf(amt));
            detailPacks.setPrices(String.valueOf(unitPrice));
        }
        detailPackMapper.savePcSlipPackDetail(list);
        return ResponseInfo.ok(i);
    }
}
